package course.dao;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * 所有Dao共有的功能，BaseDao用于继承
 *
 * @author HLF
 * @since 2022/5/12 17:05
 * <p>
 * 泛型T由子类确定的类型
 */
public abstract class BaseDao<T> {
    private QueryRunner runner = new QueryRunner();

    //因为ResultSetHandler的子类构造方法需要Class对象，所以要使用反射把子类的类型取出来
    private Class<T> type;//定义⼀个变量来接收泛型的类型

    //构造方法，也就是在创建子类对象的时候，会调用父类的构造方法
    //获取T的Class对象，获取泛型的类型，泛型是在被⼦类继承时才确定
    public BaseDao() {
        //获取子类的类型
        Class clazz = this.getClass();//BookDaoImpl.class
        //获取父类的类型
        //getGenericSuperclass()⽤来获取当前类的⽗类的类型
        //parameterizedType 表示带泛型的类型
        ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
        //获取具体的泛型类型
        //返回一个type数组
        Type[] types = parameterizedType.getActualTypeArguments();
        //获取具体泛型类型
        this.type = (Class<T>) types[0];
        //System.out.println(type);//class bookstore.entity.Books
    }

    /**
     * 增删改操作
     */
    public int update(Connection connection, String sql, Object... params) {
        int row = 0;
        try {
            row = runner.update(connection, sql, params);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return row;
    }

    /**
     * 添加操作，返回新增主键id
     */
    public int insert(Connection connection, String sql, Object... params){
        int key = 0;
        try {
            ScalarHandler<BigInteger> scalarHandler = new ScalarHandler<>();
            key =  Integer.parseInt(runner.insert(connection, sql,scalarHandler, params).toString());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return key;
    }

    /**
     * 查询一个记录对象
     */
    public T getOneBean(Connection connection, String sql, Object... params) {
        T bean = null;
        try {
            bean = runner.query(connection, sql, new BeanHandler<>(type), params);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return bean;
    }

    /**
     * 查询多个对象，返回List
     */
    public List<T> getBeanList(Connection connection, String sql, Object... params) {
        List<T> list = null;
        try {
            list = runner.query(connection, sql, new BeanListHandler<>(type), params);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    /**
     * 获取单个值
     */
    public Object getCount(Connection connection, String sql, Object... params) {
        Object count = null;
        try {
            count = runner.query(connection, sql, new ScalarHandler<>(), params);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return count;
    }
}
